﻿using System;
using OnTheWay.Interfaces;
using OnTheWay.Exceptions;
using System.Collections;
using System.ComponentModel;
using OnTheWay.Models;
using System.Windows;
using System.Collections.Generic;

namespace OnTheWay.Functions
{
    public abstract class FunctionCtrlModel<T> : FunctionCtrlModelBase where T : Model
    {
        protected IObjectBasicBehaviors<T, Guid> mDomain;

        public FunctionCtrlModel()
        {

        }

        public FunctionCtrlModel(IObjectBasicBehaviors<T, Guid> domain)
            :this()
        {
            this.mDomain = domain;
        }

        protected override void OnInitialized(EventArgs e)
        {
            base.OnInitialized(e);
            this.OnInitializeCheckItems(typeof(T));
        }

        protected virtual bool OnCanSave(T model)
        {
            return base.OnCanSave(model);
        }

        #region 数据源

        private T model;

        public T Model
        {
            get { return model; }
            set { model = value; this.PropertyNotifyChanged("Model"); }
        }

        #endregion

        #region 实现命令功能

        private void DelegateSubmit(object obj, string operate, Action<T> domain, Action<T> finish)
        {
            T model = Model;
            if (obj is T)
            {
                model = (T)obj;
            }
            if (model == null || mDomain == null || !OnCanSave(model))
            {
                return;
            }
            PostTask(() =>
            {
                DispatchWaitMessage = "正在" + operate + "数据....";
                DispatchWaitVisibility = System.Windows.Visibility.Visible;
                try
                {
                    domain.Invoke(model);
                    DispatchMessageStatus = Enums.MessageStatusEnum.Success;
                    DispatchMessage = operate + "数据成功完成";
                    finish.Invoke(model);
                }
                catch (System.Exception ex)
                {
                    DispatchMessageStatus = Enums.MessageStatusEnum.Error;
                    DispatchMessage = operate + "数据失败：" + ExceptionHandle.GetMessage(ex);
                }
                DispatchWaitVisibility = System.Windows.Visibility.Hidden;
            });
        }

        protected override void OnCommandSave(object obj)
        {
            switch (OperateMode)
            {
                case OperateModeEnum.Add:
                    this.OnCommandAdd(obj);
                    break;
                case OperateModeEnum.Modify:
                    this.OnCommandModify(obj);
                    break;
            }
        }

        protected override void OnCommandAdd(object obj)
        {
            this.DelegateSubmit(obj, "添加", x => OnTaskAdding(x), x => OnModelAdded(x));
        }

        protected override void OnCommandModify(object obj)
        {
            this.DelegateSubmit(obj, "提交", x => OnTaskModifying(x), x => OnModelModifyed(x));
        }

        protected override bool OnCanCommandAdd(object obj)
        {
            return this.OnCanCommandSave(obj);
        }

        protected override bool OnCanCommandModify(object obj)
        {
            return base.OnCanCommandModify(obj);
        }

        #endregion

        #region 预留接口
        /// <summary>
        /// 正在添加数据（异步线程中执行）
        /// </summary>
        /// <param name="model"></param>
        protected virtual void OnTaskAdding(T model)
        {
            mDomain.Insert(model);
        }

        /// <summary>
        /// 正在修改数据（异步线程中执行）
        /// </summary>
        /// <param name="model"></param>
        protected virtual void OnTaskModifying(T model)
        {
            mDomain.Update(model);
        }

        /// <summary>
        /// 添加数据完成（异步线程中执行）
        /// </summary>
        /// <param name="model"></param>
        protected virtual void OnModelAdded(T model)
        {
            DispatcherInvokeSafety(() =>
            {
                OnCommandClose(null);
                if (mActionAdded != null)
                {
                    mActionAdded(model);
                }
            }, "FunctionCtrlModel向列表页面回调添加完成（mActionAdded）时出现异常");
        }

        /// <summary>
        /// 修改数据完成（异步线程中执行）
        /// </summary>
        /// <param name="model"></param>
        protected virtual void OnModelModifyed(T model)
        {
            DispatcherInvokeSafety(() =>
            {
                OnCommandClose(null);
                if (mActionEdited != null)
                {
                    mActionEdited(model);
                }
            }, "FunctionCtrlModel向列表页面回调添加完成（mActionEdited）时出现异常");
        }


        #endregion

        #region 列表管理互交

        protected Action<T> mActionAdded;
        protected Action<T> mActionEdited;

        /// <summary>
        /// 设置当Model成功添加编辑时候 委托（一般主要用于更新列表）
        /// </summary>
        /// <param name="action"></param>
        public void SetOnAdded(Action<T> action)
        {
            mActionAdded = action;
        }
        /// <summary>
        /// 设置当Model成功完成编辑时候 委托（一般主要用于更新列表）
        /// </summary>
        /// <param name="action"></param>
        public void SetOnEdited(Action<T> action)
        {
            mActionEdited = action;
        }
        /// <summary>
        /// 初始化 Model （由子类来实现）
        /// </summary>
        /// <param name="model">为null表示需要添加，否则编辑</param>
        /// <returns>返回一个Model（添加时候 new Model）会赋值给 this.Model</returns>
        public abstract T OnInitializeModel(T model);

        #endregion
    }

    public abstract class FunctionCtrlModelBase : FunctionCtrlWait
    {
        #region 操作信息

        public enum OperateModeEnum
        {
            Read, Add, Modify
        }

        private OperateModeEnum mOperateMode = OperateModeEnum.Read;

        public OperateModeEnum OperateMode
        {
            get { return mOperateMode; }
            set { mOperateMode = value; PropertyNotifyChanged("OperateMode"); }
        }

        public string TextConfirm
        {
            get { return (string)GetValue(TextConfirmProperty); }
            set { SetValue(TextConfirmProperty, value); }
        }

        // Using a DependencyProperty as the backing store for TextConfirm.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TextConfirmProperty =
            DependencyProperty.Register("TextConfirm", typeof(string),
            typeof(FunctionCtrlModelBase), new UIPropertyMetadata("确定"));

        public string TextCancel
        {
            get { return (string)GetValue(TextCancelProperty); }
            set { SetValue(TextCancelProperty, value); }
        }

        // Using a DependencyProperty as the backing store for TextCancel.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TextCancelProperty =
            DependencyProperty.Register("TextCancel", typeof(string),
            typeof(FunctionCtrlModelBase), new UIPropertyMetadata("取消"));

        #endregion

        #region 完整性检查

        protected virtual void OnInitializeCheckItems(Type type)
        {
            if (type.IsDefined(typeof(DataBaseTableAttribute), false))
            {
                foreach (var item in type.GetProperties())
                {
                    if (item.IsDefined(typeof(DataBaseMemberAttribute), false))
                    {
                        DataBaseMemberAttribute member = item.GetCustomAttributes(typeof(DataBaseMemberAttribute), false)[0] as DataBaseMemberAttribute;
                        if (member.NotNullable)
                        {
                            if (!String.IsNullOrEmpty(member.Detail))
                            {
                                this.AddCheck(item.Name, member.Detail);
                            }
                            else
                            {
                                this.AddCheck(item.Name, item.Name);
                            }
                        }
                    }
                }
            }
        }

        private List<KeyValuePair<String, String>> mCheckItems = new List<KeyValuePair<String, String>>();

        /// <summary>
        /// 添加不为空限定条件
        /// </summary>
        /// <param name="prepertyName">限定属性名</param>
        /// <param name="displayName">属性的界面显示名称</param>
        public void AddCheck(string prepertyName, string displayName)
        {
            mCheckItems.Add(new KeyValuePair<String, String>(prepertyName, displayName));
        }

        protected bool OnCanSave(object model)
        {
            Type type = model.GetType();
            foreach (var pair in this.mCheckItems)
            {
                try
                {
                    object obj = type.GetProperty(pair.Key + "").GetValue(model, null);
                    if (obj == null)
                    {
                        this.MessageStatus = Enums.MessageStatusEnum.Warning;
                        this.Message = "【" + pair.Value + "】 不能为空。";
                        return false;
                    }
                    if (obj is String && string.IsNullOrEmpty(obj + ""))
                    {
                        this.MessageStatus = Enums.MessageStatusEnum.Warning;
                        this.Message = "【" + pair.Value + "】 不能为空。";
                        return false;
                    }
                    if (obj is Guid)
                    {
                        if (new Guid(obj + "") == Guid.Empty)
                        {
                            this.MessageStatus = Enums.MessageStatusEnum.Warning;
                            this.Message = "【" + pair.Value + "】 不能为空。";
                            return false;
                        }
                    }
                }
                catch (Exception ex)
                {
                    ExceptionHandle.Handle(ex, type.Name + " 执行OnCanSave出现异常");
                    this.MessageStatus = Enums.MessageStatusEnum.Error;
                    this.Message = "检查数据完整性出错：" + ExceptionHandle.GetMessage(ex);
                    return false;
                }
            }
            return true;
        }


        #endregion

    }
}
